#pragma once
#include <string>
#include <sys/stat.h>
#include <iostream>
#include <sys/time.h>
#include <fstream>
#include <atomic>
#include <functional>
#include <unistd.h>
#include <sys/stat.h>
#include <unordered_set>
#include <boost/algorithm/string.hpp>
#include <dirent.h>
#include <memory>
namespace ns_Util{
    // mkdir("./temp/",0744);
    class TimeUtil{
        public:
        static time_t GetNowSecondTimeStamp()
        {
            struct timeval tv;
            gettimeofday(&tv,nullptr);
            return tv.tv_sec;
            return tv.tv_usec;//微秒级时间戳，返回值类型suseconds_t
        }
        static int64_t GetNowMillisecondSecondTimeStamp()
        {
            struct timeval tv;
            gettimeofday(&tv,nullptr);
            return tv.tv_usec/1000 + tv.tv_sec*1000;
        }
        static std::string GetNowTimeString()
        {
            time_t rawtime;
            time(&rawtime);
            struct tm * timeinfo;
            timeinfo = localtime(&rawtime);
            char buffer[80];
            strftime(buffer, sizeof(buffer), "%Y-%m-%d %H:%M:%S", timeinfo);

            return buffer;
        }
    };
    class DirectUtil{
        public:
        //创建目录，mode仅在目录不存在时有效
        static int createDirectory(const std::string & dirpath,int mode = S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH) {
            const char* dirPath = dirpath.c_str();
            // 使用stat结构体和stat()函数检查目录是否存在
            struct stat info;
            if(stat(dirPath, &info) != 0) {
                // 如果目录不存在，则尝试创建
                if(mkdir(dirPath,mode) == -1) {
                    return -1; // 创建失败
                }
            } else if(!S_ISDIR(info.st_mode)) {
                printf("%s 是一个文件，而不是目录。\n", dirPath);
                return -1;
            } else {
                // 目录已经存在
                return 0;
            }
            return 0; // 成功创建或目录已存在
        }
        static void cleanDirectoryByFilename(const std::string& directoryPath, const std::string& keyword, bool verbose = false)
        {
            std::vector<std::string> files;
            getFilesWithKeyword(directoryPath, files, keyword);

            for (const auto& filePath : files)
            {
                if (remove(filePath.c_str()) == 0)
                {
                    if (verbose)
                    {
                        std::cout << "Deleted: " << filePath << std::endl;
                    }
                }
                else
                {
                    std::cerr << "Failed to delete: " << filePath << std::endl;
                }
            }
        }

        static void getFilesWithKeyword(const std::string& path, std::vector<std::string>& filenames, const std::string& keyword)
        {
            DIR *pDir;
            struct dirent* ptr;
            if ((pDir = opendir(path.c_str())) == nullptr)
            {
                std::cerr << "Error opening directory: " << path << std::endl;
                return;
            }

            while ((ptr = readdir(pDir)) != nullptr)
            {
                if (strcmp(ptr->d_name, ".") != 0 && strcmp(ptr->d_name, "..") != 0)
                {
                    std::string fileName = ptr->d_name;
                    if (fileName.find(keyword) != std::string::npos)
                    {
                        filenames.push_back(path + "/" + fileName);
                    }
                }
            }

            closedir(pDir);
        }

    };
    class TempPathUtil{
        public:
        const static std::string temp_path;
        static std::string AddSuffix(const std::string file_name,const std::string& suffix)
        {
            return temp_path + file_name+ suffix;
        }
        //提供文件路径以及后缀名称处理
        static std::string FormSrc(const std::string& FileName)
        {
            return AddSuffix(FileName,".cpp");
        }

        //提供可执行程序的路径以及后缀名
        static std::string FormExe(const std::string& FileName)
        {
            return AddSuffix(FileName,".exe");
        }
        static std::string StdinPath(const std::string &file_name)
        {
            return AddSuffix(file_name,".stdin");
        }
        static std::string StdoutPath(const std::string &file_name)
        {
            return AddSuffix(file_name,".stdout");
        }
        static std::string StderrPath(const std::string &file_name)
        {
            return AddSuffix(file_name,".stderr");
        }
        //提供错误文件的文件路径，以及后缀名
        static std::string FormError(const std::string& FileName)
        {
            return AddSuffix(FileName,".error");
        }
        static int createTempDirectory() {
            return DirectUtil::createDirectory(temp_path);
        }
    };
const std::string TempPathUtil::temp_path = "./temp/";
    class FileUtil{
        public:
        static bool IsExistFile(const std::string& path_name)
        {
            //man 2 stat
            struct stat st;
            if(!stat(path_name.c_str(),&st))
            {
                //获取属性成功，文件存在
                return 1;
            }
            return 0;
        }
        /*生成的文件名唯一性只保证在temp目录下*/
        static std::string TempPathUniqFilename()
        { 
            std::string ms = std::to_string(TimeUtil::GetNowMillisecondSecondTimeStamp());
            static std::atomic_int64_t id(0);
            std::string uniq_id = std::to_string(++id);
            return uniq_id + ms;
        }
        static bool WriteToFile(const std::string&filename,std::string &content)
        {   
            std::fstream fs(filename,std::fstream::out);
            if(!fs.is_open())
            {
                std::cerr<<"打开文件失败,文件："<<__FILE__<<"行号："<<__LINE__<<std::endl;
                return 0;
            }
            fs.write(content.c_str(),content.size());
            fs.close();
            return 1;
        }
        static std::shared_ptr<char> ReadFileBinary(const std:: string &filename,size_t *size)
        {
            *size = 0;
            std::ifstream file(filename, std::ios::binary);
            if (!file.is_open()) {
                std::cerr << "无法打开文件: " << filename << std::endl;
                return nullptr;
            }

            // 获取文件大小
            file.seekg(0, std::ios::end);
            std::fstream::pos_type fileSize = file.tellg();
            file.seekg(0, std::ios::beg);

            // 分配空间
            std::shared_ptr<char> buffer(new char[fileSize], std::default_delete<char[]>());

            // 读取文件内容
            file.read(buffer.get(), fileSize);
            *size=  fileSize;
            // 关闭文件
            file.close();
            return buffer;
        }
        //适用于读取字符文本类，如果读取二进制文件，则会出现不可预料的结果
        static std::string ReadFileToString(const std:: string &filename)
        {
            std::fstream ifs(filename,std::fstream::in | std::fstream::out);
            if(!ifs.is_open())
            {
                //读取失败，返回空串
                return "";
            }
            char tempstring[4096] = {0};
            std::string ans = "";
            while(!ifs.eof())
            {
                ifs.read(tempstring,sizeof(tempstring));
                ans+=tempstring;
            }
            // std::string tempstring;
            // std::string ans;
            // while(!ifs.eof())
            // {
            //     std::getline(ifs,tempstring);
            //     ans+=tempstring +"\n";
            // }
            ifs.close();
            return ans;
        }
    };
    
      class RAII{
        public:
        std::function<void()> _func;
        RAII(const std::function<void()>& task = [](){})
        :_func(task)
        {

        }
        //注意，类模板参数传递引用时，如果需要传递 不可被拷贝的 需要使用 std:ref
        template <class __Func,class ...__Args>
        RAII(__Func func,__Args... args)
        {
            _func= std::bind(func,args...);
        }
        ~RAII()
        {
            _func();
        }
    };
    class StringUtil{
        public:
        //输出分割后的字符串，保证原序分割，认为分隔符时单个字符，支持重复分割字符传递
        static std::vector<std::string> SepString(const std::string& s, const std::string & sepOp)
        {
            std::vector<std::string> out;
            boost::split(out,s,boost::is_any_of(sepOp),boost::algorithm::token_compress_on);
            return out;
        }
        //去除该字符串#号之后,包含#的内容
        static std::string RemoveAfterHash(const std::string &s)
        {
            std::string::size_type pos = s.find('#');
            if(pos!=std::string::npos)
            {
                return s.substr(0,pos);
            }
            return s;
        }
    };
};